/*
 * @(#)XfvhdlWindow.java        3.0                            2004/09/14
 *
 * This file is part of Xfuzzy 3.0, a design environment for fuzzy logic
 * based systems.
 *
 * (c) 2000 IMSE-CNM. The authors may be contacted by the email address:
 *                    xfuzzy-team@imse.cnm.es
 *
 * Xfuzzy is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 *
 * Xfuzzy is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 */

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
//	    VENTANA GR�FICA PARA XFVHDL3							
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//

package xfuzzy.xfvhdl;

import xfuzzy.lang.*;
import xfuzzy.*;
import xfuzzy.util.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;

/**
* Clase que gestiona la ventana gr�fica de la herramienta de s�ntesis de 
* sistemas difusos Xfvhdl3. 
* Lo que hace b�sicamente es dibujar la ventana por pantalla, esperar
* a que el usuario indique las opciones deseadas y generar una l�nea de 
* comandos que le pasa a la ejecuci�n por consola de Xfvhdl3.
* @author Jos� Mar�a �vila Maireles, <b>e-mail</b>: josavimai@alum.us.es
* @version 3.0
*/
public class XfvhdlWindow
	extends JFrame
	implements ActionListener, WindowListener, MouseListener, KeyListener {
	
	/**
	 * C�digo asociado a la clase serializable
	 */
	private static final long serialVersionUID = 95505666603081L;

	private Xfuzzy xfuzzy;
	private Specification spec;
	private XTextForm filesInformation[];
	private XTextForm numBitsInformation[];
	private XCommandForm commandform;
	private XComboBox otherInformation[];
	private XComboBox otherInformation2[];
	private XComboBox mapEffort[];
	private XComboBox optimization[];
	private JCheckBox complementaryFiles;
	private XTextForm extraParameters;
	private XTextForm device;
	private XTextForm family;
	private int synth = 0;
	JFrame j;

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	//			    CONSTRUCTORES			
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//

	/** Constructor que recibe un objeto xfuzzy y una especificaci�n XFL3.
	 * @param xfuzzy Objeto xfuzzy que ha llamado a Xfvhl3
	 * @param spec Especificaci�n XFL3 del sistema difuso
	 */
	public XfvhdlWindow(Xfuzzy xfuzzy, Specification spec) {
		super("Xfvhdl");
		this.xfuzzy = xfuzzy;
		this.spec = spec;
		build();
	}

	/** Constructor que recibe un objeto xfuzzy.
	 * @param xfuzzy Objeto xfuzzy que ha llamado a Xfvhl3
	 */

	public XfvhdlWindow(Xfuzzy xfuzzy) {
		super("Xfvhdl");
		this.xfuzzy = xfuzzy;

		if (xfuzzy != null) {
			XfvhdlProperties.outputDirectory =
				xfuzzy.getWorkingDirectory().getAbsolutePath();
		}

		build();
		setVisible(true);
	}

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	//		FUNCIONES DE CREACION DE LA VENTANA		
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//

	/** M�todo que crea la ventana gr�fica .
	 */

	@SuppressWarnings({ "unchecked", "rawtypes" })
	private void build() {

		// Defino los botones y comandos asociados para la secci�n "Files 
		// and directories information"
		String filesInformationLabels[] =
			{
				"Input XFL file",
				"Prefix for Output files",
				"Output directory",
				"Components library directory" };
		String filesInformationCommands[] =
			{
				"SelectXFLFile",
				"",
				"SelectOutputDirectory",
				"SelectLibraryDirectory" };

		// Creo la secci�n "Files and directories information"
		filesInformation = new XTextForm[4];
		for (int i = 0; i < 4; i++) {
			if (i == 1) {
				filesInformation[i] = 
				   new XTextForm(filesInformationLabels[i]);
			} else {
				filesInformation[i] =
					new XTextForm(filesInformationLabels[i], this);
				filesInformation[i].setActionCommand(
					filesInformationCommands[i]);
			}
			filesInformation[i].setEditable(true);
			filesInformation[i].setFieldWidth(250);
		}
		XTextForm.setWidth(filesInformation);

		filesInformation[0].setText(spec.getFile().getAbsolutePath());
		filesInformation[1].setText(XfvhdlProperties.outputFile);
		filesInformation[2].setText(
			XfvhdlProperties.userDirectory
				+ XfvhdlProperties.fileSeparator
				+ XfvhdlProperties.outputDirectory);
		filesInformation[3].setText(XfvhdlProperties.libraryDirectory);

		// Creamos el comboBox para seleccionar la memoria que se usar�
		otherInformation = new XComboBox[1];
		otherInformation[0] = new XComboBox("Memory to be used");

		Vector list1 = new Vector();
		list1.add("ROM  (default)");
		list1.add("RAM Block");
		list1.add("RAM Distributed");
		list1.add("Combinational logic");

		otherInformation[0].setList(list1);
		otherInformation[0].setSelectedIndex(0);

		// Creamos el comboBox para seleccionar la optimizaci�n
		optimization = new XComboBox[1];
		optimization[0] = new XComboBox("Optimization             ");

		Vector opti = new Vector();
		opti.add("Without optimization");
		opti.add("Area optimization");
		opti.add("Speed optimization");
		opti.add("Area and Speed optimizations");

		optimization[0].setList(opti);
		optimization[0].setSelectedIndex(0);

		Box modelbox = new Box(BoxLayout.Y_AXIS);
		modelbox.add(new XLabel("Files and directories information"));
		for (int i = 0; i < filesInformation.length; i++)
			modelbox.add(filesInformation[i]);

		// Pongo en la ventana la seccion "Implementation information"
		modelbox.add(Box.createVerticalStrut(5));
		modelbox.add(new XLabel("Implementation information"));
		for (int i = 0; i < otherInformation.length; i++)
			modelbox.add(otherInformation[i]);

		// Pongo en la ventana la seccion "Syntesis optimization 
		// information"
		modelbox.add(Box.createVerticalStrut(5));
		modelbox.add(new XLabel("Syntesis optimization information"));
		for (int i = 0; i < optimization.length; i++)
			modelbox.add(optimization[i]);

		// Pongo en la ventana la secci�n de "FPGA family information"
		modelbox.add(Box.createVerticalStrut(5));
		modelbox.add(new XLabel("FPGA family information"));
		family = new XTextForm("FPGA Family               ");
		family.setText(XfvhdlProperties.target);
		modelbox.add(family);

		// Pongo en la ventana la secci�n de "Extra parameters"
		modelbox.add(Box.createVerticalStrut(5));
		modelbox.add(new XLabel("Extra parameters information"));
		extraParameters = new XTextForm("Extra parameters      ");
		modelbox.add(extraParameters);

		// Defino los botones asociados para la secci�n "Bits number 
		// information"
		String numBitsInformationLabels[] =
			{
				"Bits for I/O",
				"Bits for membership degree",
				"Bits for defuzzification weight",
				"Bits for membership function slope" };

		// Creo la secci�n "Bits number information"
		numBitsInformation = new XTextForm[4];
		for (int i = 0; i < numBitsInformation.length; i++) {
			numBitsInformation[i] = 
			   new XTextForm(numBitsInformationLabels[i]);
			numBitsInformation[i].setEditable(true);
			numBitsInformation[i].setFieldWidth(100);
		}

		Integer intTmp = new Integer(XfvhdlProperties.N);
		numBitsInformation[0].setText(intTmp.toString());
		intTmp = new Integer(XfvhdlProperties.grad);
		numBitsInformation[1].setText(intTmp.toString());
		intTmp = new Integer(XfvhdlProperties.K);
		numBitsInformation[2].setText(intTmp.toString());

		// Creamos el comboBox para seleccionar herramienta de sintesis
		otherInformation2 = new XComboBox[1];
		otherInformation2[0] = new XComboBox("Tool  ");

		Vector list2 = new Vector();
		list2.add("Xilinx XST");
		list2.add("Synopsys FPGA Express");
		list2.add("Synopsys FPGA Compiler 2");

		otherInformation2[0].setList(list2);
		otherInformation2[0].setSelectedIndex(0);

		// Creamos el comboBox para seleccionar el map Effort
		mapEffort = new XComboBox[1];
		mapEffort[0] = new XComboBox("Effort");

		Vector meff = new Vector();
		meff.add("Low");
		meff.add("High");

		mapEffort[0].setList(meff);
		mapEffort[0].setSelectedIndex(0);

		int evollength = numBitsInformation.length;
		XTextForm tform[] = new XTextForm[evollength];
		for (int i = 0; i < numBitsInformation.length; i++)
			tform[i] = numBitsInformation[i];
		XTextForm.setWidth(tform);

		Box evolbox = new Box(BoxLayout.Y_AXIS);

		evolbox.add(Box.createVerticalStrut(3));

		// Pongo en la ventana la seccion "Bitsize information"
		evolbox.add(new XLabel("Bitsize information"));
		for (int i = 0; i < numBitsInformation.length; i++)
			evolbox.add(numBitsInformation[i]);
		evolbox.add(Box.createVerticalGlue());

		// Pongo en la ventana la seccion "Synthesis tool information"
		evolbox.add(Box.createVerticalStrut(5));
		evolbox.add(new XLabel("Synthesis tool information"));
		for (int i = 0; i < otherInformation2.length; i++)
			evolbox.add(otherInformation2[i]);

		// Pongo en la ventana la seccion "Map effort used in synthesis 
		// information"
		evolbox.add(Box.createVerticalStrut(5));
		evolbox.add(new XLabel("Map effort used in synthesis information"));
		for (int i = 0; i < mapEffort.length; i++)
			evolbox.add(mapEffort[i]);

		// Pongo en la ventana la secci�n de "FPGA device information"
		evolbox.add(Box.createVerticalStrut(5));
		evolbox.add(new XLabel("FPGA device information"));
		device = new XTextForm("Device");
		device.setText(XfvhdlProperties.partType);
		evolbox.add(device);

		// Pongo en la ventana la secci�n de "Complementary files 
		// information"
		evolbox.add(Box.createVerticalStrut(5));
		evolbox.add(new XLabel("Complementary files information"));
		complementaryFiles = new JCheckBox(" Generate complementary files");
		complementaryFiles.setAlignmentX((float) 1.0);
		evolbox.add(complementaryFiles);

		Box body = new Box(BoxLayout.X_AXIS);
		body.add(modelbox);
		body.add(Box.createHorizontalStrut(5));
		body.add(evolbox);

		String formlb[] =
			{ "Generate VHDL code", "Generate and Synthetize", "Close" };
		commandform = new XCommandForm(formlb, formlb, this);
		commandform.setCommandWidth(200);
		commandform.block();

		Container content = getContentPane();
		content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));
		content.add(
			new XLabel(
				"Build Synthesizable VHDL implementation for "
					+ spec));
		content.add(new XLabel("VHDL generation options"));
		content.add(body);
		content.add(commandform);

		setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
		addWindowListener(this);
		pack();
		setLocation();
	}

	/** M�todo que indica en que localizaci�n de la pantalla hay que 
	 * dibujar la ventana. 
	  */
	public void setLocation() {
		if (xfuzzy != null) {
			Point loc = xfuzzy.frame.getLocationOnScreen();
			loc.x += 40;
			loc.y += 200;
			setLocation(loc);
		} else {
			Dimension frame = getSize();
			Dimension screen = getToolkit().getScreenSize();
			setLocation(
				(screen.width - frame.width) / 2,
				(screen.height - frame.height) / 2);
		}
	}

	/** M�todo encargado de mostrar la ventana de selecci�n del directorio 
	 * de salida.
	 */
	private void selectOutputDirectory() {
		File wdir = new File(XfvhdlProperties.outputDirectory
		/*System.getProperty("user.dir")*/
		);

		XFileChooser chooser = new XFileChooser(wdir, XFileChooser.SELECT);
		chooser.setTitle("Select output directory");
		chooser.addFileFilter(".", "Directories");
		int val = chooser.showDialog();
		if (val == XFileChooser.CANCELED)
			return;

		filesInformation[2].setText(chooser.getSelectedFile().toString());
	}

	/** M�todo encargado de mostrar la ventana de selecci�n del directorio 
	 * de la librer�a VHDL.
		*/
	private void selectLibraryDirectory() {
		File wdir = new File(XfvhdlProperties.outputDirectory
		/*System.getProperty("user.dir")*/
		);

		XFileChooser chooser = new XFileChooser(wdir, XFileChooser.SELECT);
		chooser.setTitle("Select library directory");
		chooser.addFileFilter(".", "Directories");
		int val = chooser.showDialog();
		if (val == XFileChooser.CANCELED)
			return;

		filesInformation[3].setText(chooser.getSelectedFile().toString());
	}

	/** M�todo encargado de generar el c�digo VHDL, sintetizarlo e 
	 * implementarlo.
	 * Lo que hace es llamar al m�todo generateVHDLCode indicando que se 
	 * desea sintetilizar e implementar.
	 * @see generateVHDLCode
		 */
	private void generateVHDLCodeAndSynthetize() {
		synth = 1;
		generateVHDLCode();
	}

	/** M�todo encargado de generar el c�digo VHDL. Lo que hace es llamar 
	 * a Xfvhdl indicandole todas las opciones que se han seleccionado en 
	 * la ventana gr�fica.
		 */
	private void generateVHDLCode() {
	 XfvhdlProperties.userDirectory = System.getProperty("user.dir", ".");
         XfvhdlProperties.fileSeparator = System.getProperty("file.separator", "\\");
	 XfvhdlProperties.inWindow = true;
	 XfvhdlProperties.ficheroXFL = filesInformation[0].getText();
				   
	 // informamos si usamos calculo aritm�tico
	 if (!numBitsInformation[3].getText().equalsIgnoreCase("")) {
 	  boolean t;
 	  t = XDialog.showQuestion( j,
			 "Bits for membership function slope specified, so it's "
			 + "implies aritmetic calculus for antecedent !");
	  if (!t) {
	   numBitsInformation[3].setText("");
	   return;
	  }
	 }

	 // tratamiento del directorio de salida
	 XfvhdlProperties.outputDirectory = filesInformation[2].getText();
	 XfvhdlProperties.outputFile = filesInformation[1].getText();
 
 	 // tratamiento del directorio de las librerias
	 String libdefault = XfvhdlProperties.userDirectory
			    + XfvhdlProperties.fileSeparator
			    + XfvhdlProperties.libraryDirectory;
	 if (!filesInformation[3].getText().equals(libdefault)) {
 	  XfvhdlProperties.libraryDirectory = filesInformation[3].getText();
	 }

	 // tratamiento de la implementacion
	 if (otherInformation[0].getSelectedIndex() == 1) {
	  XfvhdlProperties.memoryType = "RAM-Block";
	 } else if (otherInformation[0].getSelectedIndex() == 2) {
	  XfvhdlProperties.memoryType = "RAM-Distributed";
	 } else if (otherInformation[0].getSelectedIndex() == 3) {
	  XfvhdlProperties.memoryType = "Combinational Logic";
	 } else {
	  XfvhdlProperties.memoryType = "ROM";
	 }

	 //tratamiento de la herramienta de s�ntesis
	 if (otherInformation2[0].getSelectedIndex() == 1) {
	  XfvhdlProperties.synthesisTool = "FPGA_Express";
	 } else if (otherInformation2[0].getSelectedIndex() == 2) {
	  XfvhdlProperties.synthesisTool = "FPGA_Compiler_2";
	 } else {
	  XfvhdlProperties.synthesisTool = "XILINX_XST";
	 }

	 //tratamiento del map Effort
	 if (mapEffort[0].getSelectedIndex() == 1) {
	  XfvhdlProperties.mapEffort = "HIGH_MAP_EFFORT";
	 } else {
	  XfvhdlProperties.mapEffort = "LOW_MAP_EFFORT";
	 }

	 // tratamiento de la optimizacion
	 if (optimization[0].getSelectedIndex() == 1) {
	  XfvhdlProperties.areaOptimization = true;
	 } else if (optimization[0].getSelectedIndex() == 2) {
	  XfvhdlProperties.speedOptimization = true;
	 } else if (optimization[0].getSelectedIndex() == 3) {
	  XfvhdlProperties.areaOptimization = true;
	  XfvhdlProperties.speedOptimization = true;
	 }

	 // tratamiento de los ficheros complementarios
	 if (complementaryFiles.isSelected()) {
	  XfvhdlProperties.complementaryFiles = true;
	 }
 
	 // tratamiento del FPGA device
	 if (!device.getText().equals(XfvhdlProperties.partType)) {
	  XfvhdlProperties.partType = new String(device.getText());
	 }
 
	 // tratamiento del FPGA family
	 if (!family.getText().equals(XfvhdlProperties.target)) {
	  XfvhdlProperties.target = new String(family.getText());
	 }

	 // tratamiento de N
	 Integer intTmp = new Integer(numBitsInformation[0].getText());
	 if (intTmp.intValue() != XfvhdlProperties.N) {
	  XfvhdlProperties.N = intTmp.intValue();
	 }

	 // tratamiento de grad (es decir, d)
	 Integer intTmp2 = new Integer(numBitsInformation[1].getText());
	 if (intTmp2.intValue() != XfvhdlProperties.grad) {
	  XfvhdlProperties.grad = intTmp2.intValue();
	 }

	 // tratamiento de k
	 Integer intTmp3 = new Integer(numBitsInformation[2].getText());
	 if (intTmp3.intValue() != XfvhdlProperties.K) {
	  XfvhdlProperties.K = intTmp3.intValue();
	 }

	 // tratamiento de p
	 if (!numBitsInformation[3].getText().equalsIgnoreCase("")) {
	  Integer intTmp4 = new Integer(numBitsInformation[3].getText());
	  XfvhdlProperties.P = intTmp4.intValue();
	  XfvhdlProperties.calcArithmetic = true;
	 }

	 // tratamos si hay que sintetizar o no
	 if (synth == 1) {
	  XfvhdlProperties.synthesis = true;
	  XfvhdlProperties.implementation = true;
	 }

	 try {
	  // Le asociamos el xfuzzy que nos ha llamado a xfvhdl para 
	  // que pueda mostrar mensajitos en el log.
	  Xfvhdl.xfuzzy = xfuzzy;
 
 	  // Llamamos a Xfvhdl para q se ejecute en modo consola
 	  Xfvhdl.inConsoleExecution(spec,null);
 
	  // Ponemos a cero los errores y los warnings
	  XfvhdlError xerr = new XfvhdlError();
	  xerr.resetAll();
	  synth = 0;
	 }  catch (IOException e) {
	/**/ System.err.println("Ejecutando Xfvhdl "+e);
	 }
        }

	/** M�todo encargado de cerrar la ventana gr�fica.
		 */
	private void close() {
		if (xfuzzy == null)
			System.exit(0);
		else
			setVisible(false);
	}

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	//         FUNCIONES QUE DESARROLLAN LAS INTERFACES		
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//

	public void keyReleased(KeyEvent e) {
	}
	public void keyPressed(KeyEvent e) {
	}
	public void keyTyped(KeyEvent e) {
	}

	public void mouseClicked(MouseEvent e) {
	}
	public void mouseEntered(MouseEvent e) {
	}
	public void mouseExited(MouseEvent e) {
	}
	public void mousePressed(MouseEvent e) {
	}
	public void mouseReleased(MouseEvent e) {
	}

	public void actionPerformed(ActionEvent e) {
		String command = e.getActionCommand();
		if (command.equals("SelectOutputDirectory"))
			selectOutputDirectory();
		else if (command.equals("SelectLibraryDirectory"))
			selectLibraryDirectory();
		else if (command.equals("Generate VHDL code"))
			generateVHDLCode();
		else if (command.equals("Generate and Synthetize"))
			generateVHDLCodeAndSynthetize();
		else if (command.equals("Close"))
			close();
	}

	public void windowOpened(WindowEvent e) {
	}
	public void windowClosing(WindowEvent e) {
		close();
	}
	public void windowClosed(WindowEvent e) {
	}
	public void windowIconified(WindowEvent e) {
	}
	public void windowDeiconified(WindowEvent e) {
	}
	public void windowActivated(WindowEvent e) {
	}
	public void windowDeactivated(WindowEvent e) {
	}

}
